using System;
using System.Collections;
using Microsoft.Xna.Framework;

namespace WarPigs
{
    public class Map
    {
        string mapsize;                     //Mapsize in tiny, small, medium, large, or colossal
        string maptype;                     //Maptype in temperate, jungle, desert, rugged
        string resources;                   //Resource abundance in scarce, common, or abundant
        public int[,] terrainarray;         //Two dimensional array of the size of the terrain
        public int[,] resourcearray;        //Matches above but contains locations of resource
        public int[,] unitarray;            //Matches above but contains locations of units, may be deprecated
        public int[,] buildingarray;        //Matches above but contains locations of buildings, may be deprecated
        public int[,] ownershiparray;       //Contains the ownership grid of control zones, allowing the map to paint them properly
        public int[,] fogofwar;             //Fog of War array

        int sealevel;                       //Current sealevel, modifies map generation, might not be needed. TODO: Evaluate.
        int mapsizeint;
        
        public Vector2 tiles;

        int tileGrass;
        int tileDesert;
        int tileJungle;
        int tileMarsh;
        int tileMountain;
        int tileForest;
        int tileRiver;
        int tileLake;
        int tileOcean;

        int tileOil;
        int tileWood;
        int tileWind;
        int tileWater;
        int tileStone;

        //Default constructor:
        public Map()
        {
            mapsize = "test";
            maptype = "temperate";
            sealevel = 0;
        }

        //Constructor:
        public Map(string mapsize, string maptype, int sealevel, string resources)
        {
            this.mapsize = mapsize;
            this.maptype = maptype;
            this.sealevel = sealevel;
            this.resources = resources;
            this.mapsizeint = 0;
        }

        //Grid Array Creation Method
        public void Create()
        {
            //switch (this.mapsize)
            switch(mapsize)
            {
                case "test":
                    //20 tiles
                    tiles.X = 19;
                    tiles.Y = 19;
                    this.mapsizeint = 0;
                    break;

                case "duel":
                    //2772 tiles
                    tiles.X = 66;
                    tiles.Y = 42;                  
                    this.mapsizeint = 1;
                    break;

                case "small":
                    //5625
                    tiles.X = 80;
                    tiles.Y = 52;   
                    this.mapsizeint = 2;
                    break;

                case "medium":
                    //1287 tiles
                    tiles.X = 104;
                    tiles.Y = 64;   
                    this.mapsizeint = 3;
                    break;

                case "large":
                    tiles.X = 128;
                    tiles.Y = 80;   
                    this.mapsizeint = 4;
                    break;

                case "colossal":
                    tiles.X = 150;
                    tiles.Y = 150;
                    this.mapsizeint = 5;
                    break;
            }

            this.terrainarray = new int[(int)tiles.X, (int)tiles.Y];
            this.resourcearray = new int[(int)tiles.X, (int)tiles.Y];
            this.unitarray = new int[(int)tiles.X, (int)tiles.Y];
            this.buildingarray = new int[(int)tiles.X, (int)tiles.Y];
            this.ownershiparray = new int[(int)tiles.X, (int)tiles.Y];
            this.fogofwar = new int[(int)tiles.X, (int)tiles.Y];

            switch (this.maptype)
            {
                case "temperate":
                    InitTemperateArray();
                    break;
            }
            DrawMap();
            InitResourceArray();
        }

        public void InitTemperateArray()
        {
            if (terrainarray != null)
            {
                int tilesMap = (int)tiles.X * (int)tiles.Y;
                //Initializes percentages of terrain types
                double PtileGrass = tilesMap * .2;
                double PtileDesert = 0;
                double PtileJungle = 0;
                double PtileMarsh = tilesMap * .05;
                double PtileMountain = tilesMap * .2;
                double PtileForest = tilesMap * .1;
                double PtileRiver = tilesMap * .05;
                double PtileLake = tilesMap * .05;
                double PtileOcean = tilesMap * .2;

                //Round down and convert to Int
                tileGrass = (int)Math.Floor(PtileGrass);
                tileDesert = (int)Math.Floor(PtileDesert);
                tileJungle = (int)Math.Floor(PtileJungle);
                tileMarsh = (int)Math.Floor(PtileMarsh);
                tileMountain = (int)Math.Floor(PtileMountain);
                tileForest = (int)Math.Floor(PtileForest);
                tileRiver = (int)Math.Floor(PtileRiver);
                tileLake = (int)Math.Floor(PtileLake);
                tileOcean = (int)Math.Floor(PtileOcean);
            }
        }
            //CONVERSION TABLE
            //OCEAN -    0
            //GRASS -    1
            //MOUNTAIN - 2
            //LAKE -     3
            //MARSH -    4
            //JUNGLE -   5
            //FOREST -   6
            //DESERT -   7

        //Places resources depending on tile type
        public void InitResourceArray()
        {
            Random random = new Random();
            if (resourcearray != null)
            {
                for (int x = 0; x < terrainarray.GetLength(0); x++)
                {
                    for (int y = 0; y < terrainarray.GetLength(1); y++)
                    {
                        if (random.Next(0, 100) > 50)   //Makes it so resources don't appear everywhere but good god everything in this generator is atrocious
                        {
                            switch (terrainarray[x, y])
                            {
                                case 0:
                                case 3:
                                    resourcearray[x, y] = 4;    //Water on both Ocean and Lake tiles
                                    break;

                                case 1:
                                    if (terrainarray[x - 1, y] != 2 && terrainarray[x + 1, y] != 2 && terrainarray[x, y + 1] != 2 && terrainarray[x - 1, y - 1] != 2 && terrainarray[x + 1, y + 1] != 2 && terrainarray[x + 1, y - 1] != 2 && terrainarray[x - 1, y + 1] != 2 && terrainarray[x, y - 1] != 2)
                                    {
                                        resourcearray[x, y] = 3; //Grasslands without mountains get wind
                                    }
                                    else
                                        resourcearray[x, y] = 5; //Grasslands adjacent to mountains get stone
                                    break;

                                case 5:
                                case 6:
                                    resourcearray[x, y] = 2; // forests yield trees
                                    break;
                                case 7:
                                    resourcearray[x, y] = 7; // deserts yield oil
                                    break;
                            }
                        }
                        else
                            resourcearray[x, y] = 0; //no resources
                    }
                }
            }
        }

            //RESOURCE TABLE
            //NONE - 0
            //OIL - 1
            //WOOD - 2
            //WIND - 3
            //WATER - 4
            //STONE - 5

        private void DrawMap()
        {
            //Initializes variables for the size of the map.
            //In this block here, Ttiles stands for Total, where Atiles stands for Available.
            //These are calculated by taking the total of the tiles in the game, and then removing all of the tiles that will be ocean.
            int tilesMap = terrainarray.Length;
            int AtilesX = terrainarray.GetLength(0) - sealevel;
            int AtilesY = terrainarray.GetLength(1) - sealevel;
            int startX = 0;
            //int sealevelX = terrainarray.GetLength(0) * sealevel * 2;
            //int sealevelY = terrainarray.GetLength(1) * sealevel * 2;
            //int AtilesMap = TtilesMap - sealevelX;
            //AtilesMap = AtilesMap - sealevelY;

            // Create random number generator and declare random variables.
            Random random = new Random();
            int placeY = 0;
            int placeX = 0;
            int endY = 0;
            
            for(int x = 0; x < terrainarray.GetLength(0); x++)
            {
                for(int y = 0; y < terrainarray.GetLength(1); y++)
                {
                    terrainarray[x, y] = 0;
                }    
            }
            //Debugging information.
            //Console.Clear();
            //Console.WriteLine("Map size is " + terrainarray.Length.ToString());
            //Console.WriteLine("Map height is " + terrainarray.GetLength(0).ToString());
            //Console.WriteLine("Map width is " + terrainarray.GetLength(1).ToString());
            //Console.WriteLine("We have " + AtilesX + " available along the X axis,");
            //Console.WriteLine("and we have " + AtilesY + " available along the Y axis.");
            //Console.WriteLine("We're going to make the following tiles:");
            //Console.WriteLine("Mountain: " + tileMountain);
            //Console.WriteLine("Lake: " + tileLake);
            //Console.WriteLine("Press any key to begin generation.");
            //Console.ReadLine();

            /////////////////////////////
            //Creates the base landmass//
            /////////////////////////////
            for (int x = sealevel; x < AtilesX; x++)
            {
                placeY = random.Next(sealevel, sealevel + 3);
                endY = random.Next(AtilesY - 3, AtilesY);
                //Console.WriteLine("starting at " + placeY + " and ending at " + endY);
                for (int y = placeY; y < endY; y++)
                {
                    terrainarray[x, y] = 1;
                }
            }

            //Console.WriteLine();
            //Console.WriteLine("Cleaning up northern coast...");
            //Top coastline
            for (int y = sealevel; y < AtilesY; y++)
            {
                placeX = random.Next(sealevel, sealevel + 3);
                //Console.WriteLine("starting at " + 1 + " and ending at " + placeX);
                for (int x = 1; x < placeX; x++)
                {
                    terrainarray[x, y] = 0;
                }
            }

            //Console.WriteLine();
            //Console.WriteLine("Cleaning up southern coast...");
            //Bottom coastline
            for (int y = sealevel; y < AtilesY; y++)
            {
                placeX = random.Next(AtilesX - 3, AtilesX);
                //Console.WriteLine("starting at " + placeX + " and ending at " + AtilesX);
                for (int x = placeX; x < AtilesX; x++)
                {
                    terrainarray[x, y] = 0;
                }
            }

            //Console.WriteLine();
            //Console.WriteLine("Cleaning up eastern coast...");
            //Right coastline
            for (int x = sealevel; x < AtilesX; x++)
            {
                placeY = random.Next(AtilesY - 3, AtilesY);
                //Console.WriteLine("starting at " + placeX + " and ending at " + AtilesX);
                for (int y = placeY; y < AtilesY; y++)
                {
                    terrainarray[x, y] = 0;
                }
            }

            //Console.WriteLine();
            //Console.WriteLine("Cleaning up northern coast...");
            //Top coastline
            for (int x = sealevel; x < AtilesX; x++)
            {
                placeY = random.Next(sealevel, sealevel + 3);
                //Console.WriteLine("starting at " + 1 + " and ending at " + placeX);
                for (int y = 1; y < placeY; y++)
                {
                    terrainarray[x, y] = 0;
                }
            }

            /////////////////
            //Add mountains//
            /////////////////

            while (tileMountain > 0)
            {
                //Console.WriteLine("New iteration!");

                //Randomly configures size of cluster
                int row1 = random.Next(1, 3);
                int row2 = random.Next(3, 5);
                int row3 = random.Next(row1, row2);
                int cluster = row1 + row2 + row3;

                //Removes total tiles from tileMountain (NOTE: this can go negative)
                tileMountain = tileMountain - cluster;

                //Determines our starting point. This point should be far enough from the edges to not create off-map mountains.
                //We account for this by ensuring that the edges are at least as far as the longest row in the cluster.
                placeX = random.Next(sealevel, AtilesX - 10);
                placeY = random.Next(sealevel, AtilesY - 5);
                startX = placeX;

                //Draws the first row.
                for (int y = 0; y < row1; y++)
                {
                    terrainarray[placeX, placeY] = 2;
                    placeX++;
                    //Console.WriteLine("For Row 1, ");
                    //Console.WriteLine("PlaceX is " + placeX);
                    //Console.WriteLine("PlaceY is " + placeY);
                    //Console.WriteLine("StartX is " + startX);
                }
                    
                //Resets the placeX variable so there is an offset in the cluster.
                //Increments the Y variable one space over.
                placeX = random.Next(startX + 1, startX + 3);
                placeY++;

                //And the second.
                for (int y = 0; y < row2; y++)
                {
                    terrainarray[placeX, placeY] = 2;
                    placeX++;
                    //Console.WriteLine("For Row 2, ");
                    //Console.WriteLine("PlaceX is " + placeX);
                    //Console.WriteLine("PlaceY is " + placeY);
                    //Console.WriteLine("StartX is " + startX);
                }

                //Resets the placeX variable so there is an offset in the cluster.
                //Advances placeY to move the next row of mountain.
                placeX = random.Next(startX + 1, startX + 3);
                placeY++;
                    
                //Finally the third.
                for (int y = 0; y < row3; y++)
                {
                    terrainarray[placeX, placeY] = 2;
                    placeX++;
                    //Console.WriteLine("For Row 3, ");
                    //Console.WriteLine("PlaceX is " + placeX);
                    //Console.WriteLine("PlaceY is " + placeY);
                    //Console.WriteLine("StartX is " + startX);
                }
            }

            //////////////
            //Add lakes//
            /////////////

            while (tileLake > 0)
            {
                //Console.WriteLine("New iteration!");

                //Randomly confiures size of cluster
                int row1 = random.Next(1, 3);
                int row2 = random.Next(3, 5);
                int row3 = random.Next(row1, row2);
                int cluster = row1 + row2 + row3;

                //Removes total tiles from tileLake. (NOTE: this can go negative)
                tileLake = tileLake - cluster;

                //Determines our starting point. This point should be far enough from the edges to not create off-map lakes.
                //We account for this by ensuring that the edges are at least as far as the longest row in the cluster.
                //We also want to avoid overwriting other geographical features.
                placeX = random.Next(sealevel, AtilesX - 10);
                placeY = random.Next(sealevel, AtilesY - 5);

                while (terrainarray[placeX, placeY] > 1)
                {
                    placeX = random.Next(sealevel, AtilesX - 10);
                    placeY = random.Next(sealevel, AtilesY - 5);
                }

                startX = placeX;
                if (startX >= 29)
                    startX = startX - 5;

                //Draws the first row.
                for (int y = 0; y < row1; y++)
                {
                    terrainarray[placeX, placeY] = 3;
                    placeX++;
                    //Console.WriteLine("For Row 1, ");
                    //Console.WriteLine("PlaceX is " + placeX);
                    //Console.WriteLine("PlaceY is " + placeY);
                    //Console.WriteLine("StartX is " + startX);
                }

                //Resets the placeX variable so there is an offset in the cluster.
                //Increments the Y variable one space over.
                placeX = random.Next(startX + 1, startX + 3);
                placeY++;

                //And the second.
                for (int y = 0; y < row2; y++)
                {
                    terrainarray[placeX, placeY] = 3;
                    placeX++;
                    //Console.WriteLine("For Row 2, ");
                    //Console.WriteLine("PlaceX is " + placeX);
                    //Console.WriteLine("PlaceY is " + placeY);
                    //Console.WriteLine("StartX is " + startX);
                }

                //Resets the placeX variable so there is an offset in the cluster.
                //Advances placeY to move the next row of mountain.
                placeX = random.Next(startX + 1, startX + 3);
                placeY++;

                //The third.
                for (int y = 0; y < row3; y++)
                {
                    terrainarray[placeX, placeY] = 3;
                    placeX++;
                    //Console.WriteLine("For Row 3, ");
                    //Console.WriteLine("PlaceX is " + placeX);
                    //Console.WriteLine("PlaceY is " + placeY);
                    //Console.WriteLine("StartX is " + startX);
                }
            }

            ///////////////
            //Add marshes//
            ///////////////

            while (tileMarsh > 0)
            {
                //Console.WriteLine("New iteration!");

                //Randomly confiures size of cluster
                int row1 = random.Next(1, 3);
                int row2 = random.Next(3, 5);
                int row3 = random.Next(row1, row2);
                int cluster = row1 + row2 + row3;

                //Removes total tiles from tileLake. (NOTE: this can go negative)
                tileMarsh = tileMarsh - cluster;

                //Determines our starting point. This point should be far enough from the edges to not create off-map lakes.
                //We account for this by ensuring that the edges are at least as far as the longest row in the cluster.
                //We also want to avoid overwriting other geographical features.
                placeX = random.Next(sealevel, AtilesX - 10);
                placeY = random.Next(sealevel, AtilesY - 5);

                while (terrainarray[placeX, placeY] > 1)
                {
                    placeX = random.Next(sealevel, AtilesX - 10);
                    placeY = random.Next(sealevel, AtilesY - 5);
                }

                startX = placeX;
                if (startX >= 29)
                    startX = startX - 5;

                //Draws the first row.
                for (int y = 0; y < row1; y++)
                {
                    terrainarray[placeX, placeY] = 4;
                    placeX++;
                    //Console.WriteLine("For Row 1, ");
                    //Console.WriteLine("PlaceX is " + placeX);
                    //Console.WriteLine("PlaceY is " + placeY);
                    //Console.WriteLine("StartX is " + startX);
                }

                //Resets the placeX variable so there is an offset in the cluster.
                //Increments the Y variable one space over.
                placeX = random.Next(startX + 1, startX + 3);
                placeY++;

                //And the second.
                for (int y = 0; y < row2; y++)
                {
                    terrainarray[placeX, placeY] = 4;
                    placeX++;
                    //Console.WriteLine("For Row 2, ");
                    //Console.WriteLine("PlaceX is " + placeX);
                    //Console.WriteLine("PlaceY is " + placeY);
                    //Console.WriteLine("StartX is " + startX);
                }

                //Resets the placeX variable so there is an offset in the cluster.
                //Advances placeY to move the next row of mountain.
                placeX = random.Next(startX + 1, startX + 3);
                placeY++;

                //The third.
                for (int y = 0; y < row3; y++)
                {
                    terrainarray[placeX, placeY] = 4;
                    placeX++;
                    //Console.WriteLine("For Row 3, ");
                    //Console.WriteLine("PlaceX is " + placeX);
                    //Console.WriteLine("PlaceY is " + placeY);
                    //Console.WriteLine("StartX is " + startX);
                }
            }

            //////////////
            //Add jungle//
            //////////////

            while (tileJungle > 0)
            {
                //Console.WriteLine("New iteration!");

                //Randomly confiures size of cluster
                int row1 = random.Next(1, 3);
                int row2 = random.Next(3, 5);
                int row3 = random.Next(row1, row2);
                int cluster = row1 + row2 + row3;

                //Removes total tiles from tileLake. (NOTE: this can go negative)
                tileJungle = tileJungle - cluster;

                //Determines our starting point. This point should be far enough from the edges to not create off-map lakes.
                //We account for this by ensuring that the edges are at least as far as the longest row in the cluster.
                //We also want to avoid overwriting other geographical features.
                placeX = random.Next(sealevel, AtilesX - 10);
                placeY = random.Next(sealevel, AtilesY - 5);

                while (terrainarray[placeX, placeY] > 1)
                {
                    placeX = random.Next(sealevel, AtilesX - 10);
                    placeY = random.Next(sealevel, AtilesY - 5);
                }

                startX = placeX;
                if (startX >= 29)
                    startX = startX - 5;

                //Draws the first row.
                for (int y = 0; y < row1; y++)
                {
                    terrainarray[placeX, placeY] = 5;
                    placeX++;
                    //Console.WriteLine("For Row 1, ");
                    //Console.WriteLine("PlaceX is " + placeX);
                    //Console.WriteLine("PlaceY is " + placeY);
                    //Console.WriteLine("StartX is " + startX);
                }

                //Resets the placeX variable so there is an offset in the cluster.
                //Increments the Y variable one space over.
                placeX = random.Next(startX + 1, startX + 3);
                placeY++;

                //And the second.
                for (int y = 0; y < row2; y++)
                {
                    terrainarray[placeX, placeY] = 5;
                    placeX++;
                    //Console.WriteLine("For Row 2, ");
                    //Console.WriteLine("PlaceX is " + placeX);
                    //Console.WriteLine("PlaceY is " + placeY);
                    //Console.WriteLine("StartX is " + startX);
                }

                //Resets the placeX variable so there is an offset in the cluster.
                //Advances placeY to move the next row of mountain.
                placeX = random.Next(startX + 1, startX + 3);
                placeY++;

                //The third.
                for (int y = 0; y < row3; y++)
                {
                    terrainarray[placeX, placeY] = 5;
                    placeX++;
                    //Console.WriteLine("For Row 3, ");
                    //Console.WriteLine("PlaceX is " + placeX);
                    //Console.WriteLine("PlaceY is " + placeY);
                    //Console.WriteLine("StartX is " + startX);
                }
            }

            //////////////
            //Add forest//
            //////////////

            while (tileForest > 0)
            {
                //Console.WriteLine("New iteration!");

                //Randomly configures size of cluster
                int row1 = random.Next(1, 3);
                int row2 = random.Next(3, 5);
                int row3 = random.Next(row1, row2);
                int cluster = row1 + row2 + row3;

                //Removes total tiles from tileForest. (NOTE: this can go negative)
                tileForest = tileForest - cluster;

                //Determines our starting point. This point should be far enough from the edges to not create off-map forests.
                //We account for this by ensuring that the edges are at least as far as the longest row in the cluster.
                //We also want to avoid overwriting other geographical features.
                placeX = random.Next(sealevel, AtilesX - 10);
                placeY = random.Next(sealevel, AtilesY - 5);

                while (terrainarray[placeX, placeY] > 1)
                {
                    placeX = random.Next(sealevel, AtilesX - 10);
                    placeY = random.Next(sealevel, AtilesY - 5);
                }

                startX = placeX;
                if (startX >= 29)
                    startX = startX - 5;

                //Draws the first row.
                for (int y = 0; y < row1; y++)
                {
                    terrainarray[placeX, placeY] = 6;
                    placeX++;
                    //Console.WriteLine("For Row 1, ");
                    //Console.WriteLine("PlaceX is " + placeX);
                    //Console.WriteLine("PlaceY is " + placeY);
                    //Console.WriteLine("StartX is " + startX);
                }

                //Resets the placeX variable so there is an offset in the cluster.
                //Increments the Y variable one space over.
                placeX = random.Next(startX + 1, startX + 3);
                placeY++;

                //And the second.
                for (int y = 0; y < row2; y++)
                {
                    terrainarray[placeX, placeY] = 6;
                    placeX++;
                    //Console.WriteLine("For Row 2, ");
                    //Console.WriteLine("PlaceX is " + placeX);
                    //Console.WriteLine("PlaceY is " + placeY);
                    //Console.WriteLine("StartX is " + startX);
                }

                //Resets the placeX variable so there is an offset in the cluster.
                //Advances placeY to move the next row of mountain.
                placeX = random.Next(startX + 1, startX + 3);
                placeY++;

                //The third.
                for (int y = 0; y < row3; y++)
                {
                    terrainarray[placeX, placeY] = 6;
                    placeX++;
                    //Console.WriteLine("For Row 3, ");
                    //Console.WriteLine("PlaceX is " + placeX);
                    //Console.WriteLine("PlaceY is " + placeY);
                    //Console.WriteLine("StartX is " + startX);
                }
            }
        }
    }
}